//
// Created by gh on 2020/6/19.
//

#include <stdio.h>
#include <string.h>
#include "packet.h"
#include "com_fetaphon_blelibrary_utils_JniUtils.h"
#include <android/log.h>
#include <assert.h>
#include <malloc.h>

#define DEBUG 1 /* 日志开关，1为开，其它为关 */
#if (DEBUG == 1)
#define LOG_TAG "jni_packet"
#define LOGV(...)    __android_log_print( ANDROID_LOG_VERBOSE, TAG, __VA_ARGS__ )
#define LOGD(...)    __android_log_print( ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__ )
#define LOGI(...)    __android_log_print( ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__ )
#define LOGE(...)    __android_log_print( ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__ )
#else
#define LOGV(...)    NULL
#define LOGD(...)    NULL
#define LOGI(...)    NULL
#define LOGE(...)    NULL
#endif

uint8_t output[10240];

uint8_t data_analyze(uint8_t *buf, uint32_t len);

JNIEXPORT jstring JNICALL
Java_com_fetaphon_blelibrary_utils_JniUtils_getPacket(JNIEnv *env, jobject thiz, jbyteArray array) {

    jsize len = (*env)->GetArrayLength(env, array);
    LOGE("packet length : %d\n", len);
    unsigned char *buffer;
    jbyte *lib;
    lib = (jbyte *) malloc((len + 1) * sizeof(jbyte));
    (*env)->GetByteArrayRegion(env, array, 0, len, lib);
    buffer = (char *) lib;

    if (data_analyze(buffer, len) == 0) {
        memset(output, 0, 1024);
    }

    free(lib);
    return ((*env)->NewStringUTF(env, output));
}

// #pragma pack(1)
// typedef struct {
//     uint8_t head[4];
//     uint16_t length;
//     uint16_t version;
//     uint8_t trans_code;
//     uint16_t seq;
//     uint8_t data[0];
//     //uint8_t check_sum;
// } the_frame_plus_s;
// #pragma pack()

static uint8_t frame_type[4];
static uint8_t frame_ack;
static uint8_t data_cmd;
static uint8_t data_buffer[128];

void print_to_json(uint8_t *data, uint16_t len) {
    //char output[1024];
    uint32_t i = 0;
    /*
        {
            "frame_type":"",
            "ack":"",
            "cmd":"",
            "data":"",
        }
    */
    sprintf(output, "{\"frame_type\":\"%s\",\"ack\":%d,\"cmd\":%d,\"data\":[", frame_type, frame_ack,
            data_cmd);

    for (; i < len; i++) {
        sprintf(&output[strlen(output)], "%d,", data[i]);
    }

    if (len) {
        output[strlen(output) - 1] = 0;
    }

    sprintf(&output[strlen(output)], "]}");
}


//the_frame_plus_s g_tf;
uint8_t g_data[4096];
uint32_t g_data_index;
uint16_t g_data_length;
uint8_t g_transcode;

uint8_t check(const uint8_t *data, int len) {
    assert(data && len > 1);

    int i = 0;
    uint8_t result = 0;

    for (; i < len; i++) {
        result += data[i];
        //printf("%02x ", data[i]);
    }
    //printf("\r\n");
    return result;
}

uint8_t data_analyze(uint8_t *buf, uint32_t len) {
    static uint8_t state = 0;
    uint8_t c_code;
    uint8_t *pbuf;
    uint32_t i = 0;

    if (buf[0] == 'R' && buf[1] == 'P' && buf[2] == 'B' && buf[3] == 'L') {
        state = 0;
    }

    while (i < len) {
        switch (state) {
            case 0: {
                if (buf[i] == 'R') {
                    state = 1;
                } else {
                    state = 0;
                }
                g_data_index = 0;
                g_data[g_data_index++] = 'R';
            }
                break;

            case 1:
            case 2: {
                if (buf[i] == 'P') {
                    g_data[g_data_index++] = 'P';
                    state = 3;
                } else {
                    state = 0;
                }
            }
                break;

            case 3: {
                if (buf[i] == 'B') {
                    g_data[g_data_index++] = 'B';
                    state = 4;
                } else {
                    state = 0;
                }
            }
                break;

            case 4: {
                if (buf[i] == 'L') {
                    g_data[g_data_index++] = 'L';
                    state = 5;
                } else {
                    state = 0;
                }
            }
                break;

            case 5: {
                g_data[g_data_index++] = buf[i];
                g_data_length = buf[i];
                state = 6;
            }
                break;

            case 6: {
                g_data[g_data_index++] = buf[i];
                g_data_length += (uint16_t) buf[i] << 8;
                state = 7;
                printf("len:%d\r\n", g_data_length);
            }
                break;

            case 7: {
                g_data[g_data_index++] = buf[i];
                state = 8;
            }
                break;

            case 8: {
                g_data[g_data_index++] = buf[i];
                state = 9;
            }
                break;

            case 9: {
                g_data[g_data_index++] = buf[i];
                g_transcode = buf[i];
                state = 10;
                printf("trans_code:%d\r\n", g_transcode);
            }
                break;

            case 10: {
                g_data[g_data_index++] = buf[i];
                state = 11;
            }
                break;

            case 11: {
                g_data[g_data_index++] = buf[i];
                state = 12;
            }
                break;

            case 12: {
                g_data[g_data_index++] = buf[i];
                if (g_data_index >= (g_data_length - 1)) {
                    state = 13;
                }
            }
                break;

            case 13: {
                pbuf = (uint8_t *) g_data;
                c_code = check(pbuf, g_data_length - 1);
                printf("len:%d, check:0x%02x, frame check:0x%02x\r\n", g_data_length, c_code, buf[i]);
                if (c_code == buf[i]) {
                    //output
                    frame_type[0] = (g_transcode & 0x08) ? '1' : '0';
                    frame_type[1] = (g_transcode & 0x04) ? '1' : '0';
                    frame_type[2] = (g_transcode & 0x02) ? '1' : '0';
                    frame_type[3] = 0;

                    frame_ack = (g_transcode & 0x10) ? 1 : 0;
                    data_cmd = pbuf[11];
                    print_to_json(&pbuf[12], g_data_length - 12 - 1);
                }
                state = 0;
                return 1;
            }
                break;
        }

        i++;
    }
    return 0;
}